package com.atguigu.juc.locks;

import org.junit.jupiter.api.Test;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yanglin
 * @create 2024-01-07 16:51 星期日
 * description:
 */
public class SaleTickDemo {

    /**
     * 公平锁和非公平锁：
     *  公平锁：多个线程按照申请锁的顺序来获取锁，  ReentrantLock lock = new ReentrantLock(true);  //表示公平锁
     *  非公平锁：线程获取锁的顺序并不是按照申请锁的顺序，有可能后申请的线程比先申请的线程先获取到锁，
     *          在高并发的情况下，可能造成优先级反转或者饥饿状态（某个线程一直得不到锁）
     *          ReentrantLock lock = new ReentrantLock(false);  //表示非公平锁
     *          ReentrantLock lock = new ReentrantLock();  //默认为非公平锁
     *          
     *          
     * 面试题：为什么会有公平锁和非公平锁的设计？为什么默认非公平锁？
     *        什么时候用公平？什么时候用非公平？
     *   恢复线程挂起的状态到真正锁的获取还是有时间差的，从CPU的角度来看，这个时间差存在的还是很明显的，
     *   所以非公平锁更能充分利用CPU的时间片，尽量减少CPU空闲状态时间
     *   使用多线程很重要的考量点是线程切换的开销，当采用非公平锁时，当1个线程请求锁获取同步状态，然后释放同步状态，所以刚释放锁的
     *   线程在此刻再次获得同步状态的概率就很大，就减少了线程的开销
     */


    @Test
    public void testReentrantLock(){
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for (int i = 0;i<55;i++){
                ticket.sale();
            }
        },"a").start();

        new Thread(() -> {
            for (int i = 0;i<55;i++){
                ticket.sale();
            }
        },"b").start();

        new Thread(() -> {
            for (int i = 0;i<55;i++){
                ticket.sale();
            }
        },"c").start();
    }
}

class Ticket {    //资源类   模拟3个售票员卖完50张票
    
    private int number = 50;
    
    ReentrantLock lock = new ReentrantLock(true);
    
    public void sale(){
        lock.lock();
        if (number > 0){
            System.out.println(Thread.currentThread().getName() + "卖出第：" + (number--) + "张票," + "还剩：" + number);
        }
        lock.unlock();
    }
    
    
}
